// bzoj1210
// 题意：
// 给定一个n(<=20)*m(<=10)的棋盘，要从左上角出发经过所有格子返回左上角，
// 问不同路径的方案数。
//
// 题解：
// 经典的回路问题，用插头dp，算作是模板吧。参考陈丹琦《基于连通性状态压缩的动态规划问题》。
// 这里是写的按格子转移，论文面对三种情况左插头和右插头情况讨论的非常清楚。
//
// run: $exec < input
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>

struct big_integer
{
	int static const base = 1e9;
	big_integer() { clear(); }
	void clear() { std::memset(a, 0, sizeof(a)); }
	void set(int x)
	{
		clear();
		for (; x; x /= base) a[++a[0]] = x % base;
	}

	void print()
	{
		std::cout << a[a[0]];
		for (int i = a[0] - 1; i > 0; i--)
			std::cout << std::setfill('0') << std::setw(9) << a[i];
	}

	big_integer operator+(big_integer const & b)
	{
		big_integer c;
		c.a[0] = std::max(a[0], b.a[0]) + 1;
		for (int i = 1; i <= c.a[0]; i++) {
			c.a[i] += a[i] + b.a[i];
			c.a[i + 1] += c.a[i] / base;
			c.a[i] %= base;
		}
		while (!c.a[c.a[0]]) c.a[0]--;
		return c;
	}
	void operator+=(big_integer const & b) { *this = *this + b; }
	void operator= (int x) { set(x); }

	int a[10];
};

struct hash_table
{
	int static const maxsize = 2700;
	int key[maxsize];
	int hash[maxsize];
	big_integer val[maxsize];
	int count;

	void clear()
	{
		count = 0;
		std::memset(key, -1, sizeof(key));
		std::memset(hash, 0, sizeof(hash));
		std::memset(val, 0, sizeof(val));
	}

	void alloc_node(int pos, int key_)
	{
		hash[pos] = ++count; key[count] = key_;
	}

	big_integer & operator[](int key_)
	{
		int p;
		for (int i = key_ % maxsize; ; i++) {
			if (i == maxsize) i = 0;
			if (!hash[i]) alloc_node(i, key_);
			if (key[hash[i]] == key_) {
				p = hash[i];
				break;
			}
		}
		return val[p];
	}
};

hash_table f[2];
int n, m;
int now, prev;
big_integer ans;

int get(int st, int x) { return (st >> ((x - 1) << 1)) & 3; }
void change(int & st, int p, int v)
{
	int w = (p - 1) << 1;
	st &= (~0) ^ (3 << w);
	st |= v << w;
}

int find(int st, int p)
{
	for (int i = p, d = 0, step = get(st, p) == 1 ? 1 : -1; ; i += step) {
		d += get(st, i) == 1 ? 1 : -1;
		d += get(st, i) == 0 ? 1 : 0;
		if (!d) return i;
	}
	return -1;
}

void dp(int i, int j)
{
	now ^= 1; prev ^= 1;
	f[now].clear();
	for (int t = 1; t <= f[prev].count; t++) {
		int st = f[prev].key[t];
		big_integer v = f[prev].val[t];
		int left = get(st, j);
		int up = get(st, j + 1);
		// plz ref to cdq' paper, about three conditions discussion
		if (!left && !up) {
			if (i != n && j != m) {
				change(st, j, 1);
				change(st, j + 1, 2);
				f[now][st] += v;
			}
		} else if (left == up) {
			change(st, find(st, j + 2 - left), left);
			change(st, j, 0);
			change(st, j + 1, 0);
			f[now][st] += v;
		} else if (left == 1 && up == 2) {
			if (i == n && j == m) ans += v;
		} else if (left == 2 && up == 1) {
			change(st, j, 0);
			change(st, j + 1, 0);
			f[now][st] += v;
		} else if (left) {
			if (i != n) f[now][st] += v;
			if (j != m) {
				change(st, j, 0);
				change(st, j + 1, left);
				f[now][st] += v;
			}
		} else if (up) {
			if (j != m) f[now][st] += v;
			if (i != n) {
				change(st, j + 1, 0);
				change(st, j, up);
				f[now][st] += v;
			}
		}
	}
}

int main()
{
	std::ios::sync_with_stdio(false);
	std::cin >> n >> m;
	if (n < m) std::swap(n, m);
	if (m == 1) { std::cout << "1\n"; return 0; }
	f[0][0] = 1;
	now = 0; prev = 1;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) dp(i, j);
		if (i == n) continue;
		for (int j = 1; j <= f[now].count; j++)
			f[now].key[j] <<= 2;
	}
	ans += ans;
	ans.print();
}

